package com.basker.pisces.core.query.factory;

import java.util.List;

import org.springframework.core.ResolvableType;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import com.basker.pisces.core.query.QueryInfo;
import com.basker.pisces.core.query.builder.CriterionBuilder;
import com.basker.pisces.core.query.builder.QueryBuilder;
import com.basker.pisces.core.query.meta.QueryMeta;
import com.basker.pisces.spring.SpringApplicationContext;

/**
 * 构建QueryInfo是一个比较费事的工作，故设计该工厂类负责组装，每个QueryInfoFactory都可以将一个source对象转化为QueryInfo
 *
 * @param <TSource>
 * @author hangwen
 * @see #getFactory(Class)
 */
public abstract class QueryInfoFactory<TSource> {

    /**
     * 获取可以通过AggregateQueryInfo创建QueryInfo的工厂
     *
     * @return
     */
    public static QueryInfoFactory<AggregateQueryInfo> getAggregateQueryInfoFactory() {
        return getFactory(AggregateQueryInfo.class);
    }

    /**
     * 根据sourceType获取指定的工厂
     *
     * @param sourceType
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <TSource> QueryInfoFactory<TSource> getFactory(Class<TSource> sourceType) {
        Assert.notNull(sourceType, "parameter 'sourceType' is required");

        @SuppressWarnings("rawtypes")
        QueryInfoFactory defaultFactory = tryGetDefaultFactory(sourceType);
        if (defaultFactory != null) {
            return defaultFactory;
        }

        @SuppressWarnings("rawtypes")
        List<QueryInfoFactory> factorites = SpringApplicationContext.getInstance().getBeans(QueryInfoFactory.class);
        if (CollectionUtils.isEmpty(factorites)) {
            throw new IllegalStateException("No QueryInfoFactory beans in spring IOC");
        }

        for (@SuppressWarnings("rawtypes")
                QueryInfoFactory factory : factorites) {
            ResolvableType generic = ResolvableType.forInstance(factory).getSuperType().getGeneric(0);

            if (generic.resolve().equals(sourceType)) {
                return factory;
            }
        }

        throw new IllegalArgumentException("sourceType '" + sourceType.getName() + "' has no QueryInfoFactory matched");
    }

    /**
     * 获取可以通过SimpleQueryInfo创建QueryInfo的工厂
     *
     * @return
     */
    public static QueryInfoFactory<SimpleQueryInfo> getSimpleQueryInfoFactory() {
        return getFactory(SimpleQueryInfo.class);
    }

    @SuppressWarnings("unchecked")
    private static <TSource> QueryInfoFactory<TSource> tryGetDefaultFactory(Class<TSource> sourceType) {
        if (sourceType.equals(SimpleQueryInfo.class)) {
            return (QueryInfoFactory<TSource>) SpringApplicationContext.getInstance()
                    .getBean(SimpleQueryInfoFactory.class);
        }

        if (sourceType.equals(AggregateQueryInfo.class)) {
            return (QueryInfoFactory<TSource>) SpringApplicationContext.getInstance()
                    .getBean(AggregateQueryInfoFactory.class);
        }

        return null;
    }

    public abstract QueryInfo create(QueryMeta queryMeta, TSource source);

    protected void addConditions(List<Condition> conditions, QueryBuilder builder) {
        if (!CollectionUtils.isEmpty(conditions)) {
            for (Condition condition : conditions) {
                CriterionBuilder criterion = condition.createCriterionBuilder();

                if (criterion != null) {
                    builder.andCriteria(criterion);
                }
            }
        }
    }

    protected void addOrders(List<Order> orders, QueryBuilder builder) {
        if (!CollectionUtils.isEmpty(orders)) {
            for (Order order : orders) {
                builder.orderBy(order.getField(), order.isDesc());
            }
        }
    }

}
